package protocol

import (
	"alarm_protocol/common"
	"alarm_protocol/mqtt"
	"encoding/binary"
	"fmt"
	"time"

	"github.com/sirupsen/logrus"
)

// Packet represents the structure of a network packet based on the protocol
type Packet struct {
	StartDelimiter  [2]byte // 启动符
	TransactionID   uint16  // 业务流水号
	ProtocolVersion [2]byte // 协议版本号
	Timestamp       [6]byte // 时间标签
	SourceAddr      [6]byte // 源地址
	DestinationAddr [6]byte // 目的地址
	DataLength      uint16  // 应用数据单元长度
	Command         byte    // 命令字节
	Data            []byte  // 应用数据单元
	Checksum        byte    // 校验和
	EndDelimiter    [2]byte // 结束符
}

// NewPacket creates a new packet with default settings
func NewPacket() *Packet {
	return &Packet{
		StartDelimiter:  [2]byte{64, 64},
		ProtocolVersion: [2]byte{1, 1},
		EndDelimiter:    [2]byte{35, 35},
	}
}

// Serialize serializes the packet into bytes
func (p *Packet) Serialize() []byte {
	totalLength := 29 + len(p.Data)
	data := make([]byte, totalLength)

	copy(data[0:2], p.StartDelimiter[:])
	binary.LittleEndian.PutUint16(data[2:4], p.TransactionID)
	copy(data[4:6], p.ProtocolVersion[:])
	copy(data[6:12], p.Timestamp[:])
	copy(data[12:18], p.SourceAddr[:])
	copy(data[18:24], p.DestinationAddr[:])
	binary.LittleEndian.PutUint16(data[24:26], uint16(len(p.Data)))
	data[26] = p.Command
	copy(data[27:27+len(p.Data)], p.Data)

	// Calculate and set checksum
	data[27+len(p.Data)] = calculateChecksum(data[2 : 27+len(p.Data)])

	copy(data[28+len(p.Data):], p.EndDelimiter[:])

	return data
}

// calculateChecksum calculates the checksum for the given data
func calculateChecksum(data []byte) byte {
	// logrus.Debug("Calculating checksum for data: ", data)
	var sum uint16
	for _, b := range data {
		sum += uint16(b)
	}
	return byte(sum & 0xFF) // Keep only the last byte
}

// Deserialize constructs a Packet from byte slice, assuming it's correctly formed
func Deserialize(data []byte) (*Packet, error) {
	if len(data) < 29 { // Minimal length check
		return nil, fmt.Errorf("data too short to be a valid packet")
	}
	p := NewPacket()

	// Verify start delimiter
	if data[0] != 64 || data[1] != 64 {
		logrus.Debug("Start delimiter: ", data[0:2])
		return nil, fmt.Errorf("invalid start delimiter")
	}
	copy(p.StartDelimiter[:], data[0:2])

	p.TransactionID = binary.LittleEndian.Uint16(data[2:4])
	copy(p.ProtocolVersion[:], data[4:6])
	copy(p.Timestamp[:], data[6:12])
	copy(p.SourceAddr[:], data[12:18])
	copy(p.DestinationAddr[:], data[18:24])
	p.DataLength = binary.LittleEndian.Uint16(data[24:26])
	p.Command = data[26]

	// Verify data length
	if len(data) < 29+int(p.DataLength) {
		return nil, fmt.Errorf("actual data length does not match specified length")
	}

	p.Data = make([]byte, p.DataLength)
	copy(p.Data, data[27:27+int(p.DataLength)])

	p.Checksum = data[27+int(p.DataLength)]

	// Verify end delimiter
	endIndex := 28 + int(p.DataLength)
	if data[endIndex] != 35 || data[endIndex+1] != 35 {
		logrus.Debug("End delimiter: ", data[endIndex:endIndex+2])
		return nil, fmt.Errorf("invalid end delimiter")
	}
	copy(p.EndDelimiter[:], data[endIndex:endIndex+2])

	// Verify checksum
	calculatedChecksum := calculateChecksum(data[2 : 27+int(p.DataLength)])
	if p.Checksum != calculatedChecksum {
		return nil, fmt.Errorf("invalid checksum: got %d, expected %d", p.Checksum, calculatedChecksum)
	}

	return p, nil
}

// 应答
// 应答
func (p *Packet) Respond(deviceID string) ([]byte, error) {
	response := Packet{
		StartDelimiter:  [2]byte{0x40, 0x40}, // @@
		TransactionID:   p.TransactionID,     // 使用相同的业务流水号
		ProtocolVersion: p.ProtocolVersion,   // 保持相同的协议版本
		SourceAddr:      p.DestinationAddr,   // 交换源地址和目的地址
		DestinationAddr: p.SourceAddr,
		DataLength:      0,    // 默认无数据
		Command:         0x03, // 假设0x03是确认命令
		Data:            []byte{},
		EndDelimiter:    [2]byte{0x23, 0x23}, // ##
	}
	// 如果命令队列中有需要发送的命令，使用第一个命令
	commandChan := common.CommandQueues.GetQueue(deviceID)
	if commandChan != nil {
		if len(commandChan) > 0 {
			command := <-commandChan
			// 使用第一个命令
			data, err := GenerateRemoteOperationData(command)
			if err != nil {
				logrus.Errorf("Error generating remote operation data: %v", err)
				// 响应失败
				rspdata := common.Result{
					Result:  1,
					Message: fmt.Sprintf("Error generating remote operation data: %v", err),
					Method:  command.Method,
					Ts:      time.Now().UnixNano() / 1e6,
				}
				//RSPDATA转map
				rspdataMap := make(map[string]interface{})
				rspdataMap["result"] = rspdata.Result
				rspdataMap["message"] = rspdata.Message
				rspdataMap["method"] = rspdata.Method
				rspdataMap["ts"] = rspdata.Ts
				// 发送到MQTT
				err := mqtt.PublishCommandResponse(deviceID, command.MessageID, rspdataMap)
				if err != nil {
					logrus.Errorf("Error generating remote operation data: %v", err)
				}
			} else {
				response.Data = data
				response.DataLength = uint16(len(data))
				response.Command = 0x01 // 控制命令
				// 假设下面一定会发到，给平台响应结果
				rspdata := common.Result{
					Result:  0,
					Message: "success",
					Method:  command.Method,
					Ts:      time.Now().UnixNano() / 1e6,
				}
				//RSPDATA转map
				rspdataMap := make(map[string]interface{})
				rspdataMap["result"] = rspdata.Result
				rspdataMap["message"] = rspdata.Message
				rspdataMap["method"] = rspdata.Method
				rspdataMap["ts"] = rspdata.Ts
				// 发送到MQTT
				mqtt.PublishCommandResponse(deviceID, command.MessageID, rspdataMap)
			}
		}
	}

	// 设置当前时间戳
	now := time.Now()
	binary.LittleEndian.PutUint16(response.Timestamp[0:2], uint16(now.Year()-2000))
	response.Timestamp[2] = byte(now.Month())
	response.Timestamp[3] = byte(now.Day())
	response.Timestamp[4] = byte(now.Hour())
	response.Timestamp[5] = byte(now.Minute())

	// 准备用于计算校验和的数据
	checksumData := make([]byte, 0, 25+len(response.Data))
	checksumData = binary.LittleEndian.AppendUint16(checksumData, response.TransactionID)
	checksumData = append(checksumData, response.ProtocolVersion[:]...)
	checksumData = append(checksumData, response.Timestamp[:]...)
	checksumData = append(checksumData, response.SourceAddr[:]...)
	checksumData = append(checksumData, response.DestinationAddr[:]...)
	checksumData = binary.LittleEndian.AppendUint16(checksumData, response.DataLength)
	checksumData = append(checksumData, response.Command)
	checksumData = append(checksumData, response.Data...)

	// 计算校验和
	response.Checksum = calculateChecksum(checksumData)

	// 将应答包序列化为字节切片
	responseBytes := make([]byte, 0, 32+len(response.Data))
	responseBytes = append(responseBytes, response.StartDelimiter[:]...)
	responseBytes = append(responseBytes, checksumData...)
	responseBytes = append(responseBytes, response.Checksum)
	responseBytes = append(responseBytes, response.EndDelimiter[:]...)

	return responseBytes, nil
}
